package com.vipshop.compass.config.util;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class PrettyPrinter {
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("Usage: java PrettyPrinter [XML URL]");
			System.exit(0);
		}
		;

		String url = args[0];

		try {
			PrettyPrinter.printDoc(url);
		} catch (ParserConfigurationException e) {
			System.out.println("Pretty printer failed due to parser" + "configuration error.");
			System.exit(0);
		}
	};

	public static void printDoc(String url) throws ParserConfigurationException {
		System.out.println("Pretty printing XML file: " + url + ".");
		// Creating a parser factory (JAXP)
		// It can be configured at runtime, which implementation
		// (Xerces, Crimson, ...) is to be used,
		// for example via the Java systems property.
		DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
		// Configuring the parsers that the factory will create (JAXP)
		parserFactory.setValidating(true);
		parserFactory.setNamespaceAware(true);
		parserFactory.setExpandEntityReferences(true);
		// Creating a parser (JAXP)
		DocumentBuilder parser = parserFactory.newDocumentBuilder();
		try {
			// Using the parser to build the DOM document (JAXP)
			Document doc = parser.parse(url);
			// All further computations are based on DOM, no longer on JAXP.
			printNode(doc); // print nodes recursively
		} catch (Exception e) {
			System.out.println("Error in parsing: " + e.getMessage());
		}
	};

	public static void printNode(Node node) {
		// This method uses only DOM functionality.
		switch (node.getNodeType()) {
		case Node.DOCUMENT_NODE:
			System.out.println("<?xml version=\"1.0\" encoding=\"UTF8\"?>");
			Document doc = (Document) node;
			printNode(doc.getDocumentElement());
			break;
		case Node.ELEMENT_NODE:
			Element element = (Element) node;
			element.normalize();
			String name = node.getNodeName();
			System.out.print("<" + name);
			NamedNodeMap attributes = node.getAttributes();
			for (int i = 0; i < attributes.getLength(); i++) {
				Node attr = attributes.item(i);
				System.out.print(" " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\"");
			}
			;
			System.out.println(">");
			NodeList children = node.getChildNodes();
			if (children != null) {
				for (int i = 0; i < children.getLength(); i++) {
					printNode(children.item(i));
				}
				;
			}
			;
			System.out.println("</" + name + ">");
			break;
		case Node.TEXT_NODE:
		case Node.CDATA_SECTION_NODE:
			System.out.println(node.getNodeValue() + ""); // needs filtering!
			break;
		case Node.PROCESSING_INSTRUCTION_NODE:
			break;
		case Node.ENTITY_REFERENCE_NODE:
			System.out.println("&" + node.getNodeName() + ";");
			break;
		case Node.DOCUMENT_TYPE_NODE:
			break;
		}
		;
	};
}
